<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>this绑定规则的优先级(The priority of this binding rule)</title>
  <!-- 
  在JavaScript中， `this` 的绑定规则决定了在不同上下文中 `this` 的指向。理解这些规则的优先级对于编写正确的代码至关重要。以下是关于 `this` 绑定规则优先级的总结说明：
  一、 `this` 绑定规则的优先级
  1. 显式绑定：
    - 使用 `call()` 、 `apply()` 或 `bind()` 方法显式设置 `this` 的值时，这种绑定具有最高优先级。
    - 这些方法允许开发者明确指定函数在执行时的 `this` 指向。
    function greet() {
      console.log(`Hello, my name is ${this.name}`);
    }

    const person = { name: 'Alice' };
    greet.call(person); // 输出: Hello, my name is Alice
  2. 构造函数调用：
    - 当使用 `new` 关键字调用构造函数时， `this` 指向新创建的实例对象。
    - 这一规则优先于对象方法调用。
    function Person(name) {
      this.name = name;
    }

    const bob = new Person('Bob');
    console.log(bob.name); // 输出: Bob
  3. 对象方法调用：
    - 当一个函数作为对象的方法被调用时， `this` 指向调用该方法的对象。
    - 这种绑定优先于全局上下文的绑定。
    const person = {
      name: 'Charlie',
      greet: function() {
        console.log(`Hello, my name is ${this.name}`);
      }
    };

    person.greet(); // 输出: Hello, my name is Charlie
  4. 事件处理程序：
    - 在事件处理程序中， `this` 指向触发事件的元素。
    - 这种绑定优先于全局上下文的绑定。
    const button = document.getElementById('myButton');
    button.addEventListener('click', function() {
      console.log(this); // 输出: <button id="myButton">...</button>
    });
  5. 全局上下文：
    - 在全局上下文中， `this` 指向全局对象。在浏览器中， `this` 指向 `window` 对象。
    - 当函数不在任何对象的上下文中调用时， `this` 会指向全局对象。
    console.log(this); // 在浏览器中输出: Window {...}

  二、总结
  - 优先级顺序：
    1. 显式绑定（ `call` 、 `apply` 、 `bind` ）
    2. 构造函数调用（使用 `new` 关键字）
    3. 对象方法调用
    4. 事件处理程序
    5. 全局上下文
   -->
</head>
<body>

  <script>
    // 比较优先级
    // 1. 显示绑定优先级高于隐式绑定
    function foo() {
      console.log("foo: ", this);
    }
    const obj = { foo: foo }
    obj.foo.apply("apply")
    obj.foo.call("call")
    obj.foo.bind("bind")()

    // 2. bind高于默认绑定
    const bar = foo.bind("bind")
    const obj2 = {
      name: "obj2",
      bar: bar
    }
    obj2.bar()

    // 3. new优先级高于显示绑定
    function Person(name) {
      this.name = name;
      console.log("person: ", this);
      this.greet = function() {
        console.log("Hello, my name is " + this.name);
      }
    }
    const person = new Person("Charlie");
    person.greet(); // 输出: Hello, my name is Charlie

    // 4. bind优先级高于new
    const boundPerson = new (Person.bind("bind"))("Charlie");
    boundPerson.greet(); // 输出: Hello, my name is Charlie

    // 5. bind优先级高于apply/call
    const boundPerson2 = Person.bind("bind");
    boundPerson2.call("call");
    
  </script>
  
</body>
</html>